
#include <object_browser/objectstreemodel.h>

int ObjectsTreeModel::Item::GetIndex() const
{
  if (!parent)
    {
      return 0;
    }

  for (int i=0, j=parent->children.size(); i<j; ++i)
    {
      if (parent->children[i] == this)
        {
          return i;
        }
    }

  return 0;
}

void ObjectsTreeModel::Item::SingleDebug() const
{
  printf ("%d:", GetIndex());
  switch (type)
    {
    case Item::Type_Root:
      printf ("Root");
      break;
    case Item::Type_Category:
      printf ("Category: %s", category.GetFullName().toStdString().c_str());
      break;
    case Item::Type_Object:
      printf ("Object: %s", object->GetName().toStdString().c_str());
      break;
    }
}

void ObjectsTreeModel::Item::Debug(int indent) const
{
  for (unsigned i=0; i<indent; ++i)
    {
      printf ("  ");
    }
  SingleDebug();
  printf ("\n"); fflush(stdout);
  foreach (Item* child, children)
    {
      child->Debug (indent+1);
    }
}

ObjectsTreeModel::ObjectsTreeModel(ObjectManager* manager)
  : _rootItem(0)
{
  _rootItem = new Item ();
  _rootItem->type = Item::Type_Root;
	_rootItem->parent = 0;

  _pmCategory = QPixmap (":/icons/media/category.png");
  _pmObject   = QPixmap (":/icons/media/object.png");

  connect (manager, SIGNAL(ObjectAdded(SceneObject*)), this, SLOT(AddObject(SceneObject*)));
  connect (manager, SIGNAL(ObjectChanged(SceneObject*)), this, SLOT(ChangeObject(SceneObject*)));
  connect (manager, SIGNAL(ObjectMoved(SceneObject*)), this, SLOT(MoveObject(SceneObject*)));
  connect (manager, SIGNAL(ObjectRemoved(SceneObject*)), this, SLOT(RemoveObject(SceneObject*)));
}

void ObjectsTreeModel::AddObject(SceneObject *object)
{
  Item* parentItem = GetItem(object->GetCategory());

  int row = parentItem->children.count();
  beginInsertRows(CreateIndex(parentItem),
                  row,
                  row);


  Item* item = new Item ();
  item->type = Item::Type_Object;
  item->object = object;
  item->parent = parentItem;
  parentItem->children.append(item);

  endInsertRows();
}

void ObjectsTreeModel::RemoveObject(SceneObject *object)
{
  Item *item = GetItem (object);
  RemoveItem(item);
}


void ObjectsTreeModel::RemoveItem(Item *item)
{
  if (!item || item == _rootItem)
    {
      // exit at root item that must not be destroyed
      return;
    }

  Item* parent = item->parent;

  int row = item->GetIndex();
  beginRemoveRows(CreateIndex(parent),
                  row,
                  row);
  if (parent)
    {
      parent->children.removeAll(item);
    }

  delete item;
  endRemoveRows();

  if (parent && parent->children.count() == 0)
    {
      RemoveItem(parent);
    }
}

void ObjectsTreeModel::MoveObject(SceneObject *object)
{
  RemoveObject(object);
  AddObject(object);
}

void ObjectsTreeModel::ChangeObject(SceneObject *object)
{
  Item* item = GetItem(object);
  ItemChanged(item);
}

bool ObjectsTreeModel::IsCategory(const QModelIndex &index)
{
  if (!index.isValid()) return false;
  Item* item = static_cast<Item*>(index.internalPointer());
  return (item && item->type == Item::Type_Category);
}

bool ObjectsTreeModel::IsSceneObject(const QModelIndex &index)
{
  if (!index.isValid()) return false;
  Item* item = static_cast<Item*>(index.internalPointer());
  return (item && item->type == Item::Type_Object);
}

Category* ObjectsTreeModel::GetCatetory(const QModelIndex &index)
{
  if (!index.isValid()) return 0;
  Item* item = static_cast<Item*>(index.internalPointer());
  if (!item || item->type != Item::Type_Category) return 0;

  return &item->category;
}

SceneObject* ObjectsTreeModel::GetSceneObject(const QModelIndex &index)
{
  if (!index.isValid()) return 0;
  Item* item = static_cast<Item*>(index.internalPointer());
  if (!item || item->type != Item::Type_Object) return 0;

  return item->object;
}

ObjectsTreeModel::Item* ObjectsTreeModel::GetItem(const SceneObject *object)
{
  return GetItem (_rootItem, object);
}

ObjectsTreeModel::Item* ObjectsTreeModel::GetItem(Item* item, const SceneObject *object)
{
  if (    item->type == Item::Type_Object
      &&  item->object == object)
    {
      return item;
    }

  foreach (Item* child, item->children)
    {
      Item* i = GetItem(child, object);
      if (i)
        {
          return i;
        }
    }
  return 0;
}

ObjectsTreeModel::Item* ObjectsTreeModel::GetItem(const Category &category)
{
  Category cat;
  Item* item = _rootItem;
  for (int i=0; i<category.GetNumberOfStages(); i++)
    {
      cat << category.GetStageName(i);

      bool found = false;
      foreach (Item* ni, item->children)
        {
          if (   ni->type     == Item::Type_Category
              && ni->category == cat)
            {
              item = ni;
              found = true;
              break;
            }
        }

      if (!found)
        {
          int row = item->children.count();
          beginInsertRows(CreateIndex(item),
                          row,
                          row);
          Item* ni = new Item ();
          ni->type      = Item::Type_Category;
          ni->category  = cat;
          ni->object    = 0;
          ni->parent    = item;
          item->children.append(ni);
          endInsertRows();

          item = ni;
        }
    }
  return item;
}

void ObjectsTreeModel::ItemChanged(Item *item)
{
  QModelIndex idx = CreateIndex(item);
  emit dataChanged(idx, idx);
}

QModelIndex ObjectsTreeModel::CreateIndex(Item *item, int column) const
{
  if (!item || item == _rootItem)
		{
			return QModelIndex ();
		}
  return createIndex(item->GetIndex(), column, item);
}

int ObjectsTreeModel::columnCount(const QModelIndex &parent) const
{
  return 1;
}

QVariant ObjectsTreeModel::data(const QModelIndex &index, int role) const
{
  if (!index.isValid()) return QVariant ();

  const Item* item = static_cast<const Item*>(index.internalPointer());
  if (!item || item == _rootItem) return QVariant ();

  if (role == Qt::DisplayRole)
    {

      switch (item->type)
        {
        case Item::Type_Root:
          return QVariant ("");

        case Item::Type_Category:
          return QVariant (item->category.GetHeadName());

        case Item::Type_Object:
          return QVariant (item->object->GetName());

        default:
          break;
        }
    }
  else if (role == Qt::DecorationRole && index.column() == 0)
    {
      switch (item->type)
        {
        case Item::Type_Root:
          break;

        case Item::Type_Category:
          return QVariant (_pmCategory);

        case Item::Type_Object:
          return QVariant (_pmObject);
          break;

        default:
          break;
        }
    }

  return QVariant ();
}

QModelIndex ObjectsTreeModel::index(int row, int column, const QModelIndex &parent) const
{
  Item* parentItem =  0;
	if (!parent.isValid())
    {
			parentItem = _rootItem;
    }
	else
		{
			parentItem = static_cast<Item*>(parent.internalPointer());
		}
  if (!parentItem)
    {
      return QModelIndex ();
    }

  if (row >= parentItem->children.size())
    {
      return QModelIndex ();
    }


  return CreateIndex(parentItem->children[row], column);
}

QModelIndex ObjectsTreeModel::parent(const QModelIndex &index) const
{
  if (!index.isValid()) return QModelIndex ();

  Item *item = static_cast<Item*>(index.internalPointer());
  if (!item || item == _rootItem || item->parent == _rootItem)
    {
      return QModelIndex ();
    }
  return CreateIndex(item->parent);
}

int ObjectsTreeModel::rowCount(const QModelIndex &parent) const
{
  Item* parentItem = 0;
  if (!parent.isValid())
    {
      parentItem = _rootItem;
    }
  else
    {
      parentItem = static_cast<Item*>(parent.internalPointer());
    }

  if (!parentItem)
    {
      return 0;
    }


  return parentItem->children.count();
}

void ObjectsTreeModel::Debug ()
{
  _rootItem->Debug();
}

